//
//  LRNetworkTool.swift
//  LRWeibo
//
//  Created by 雷路荣 on 15/12/18.
//  Copyright © 2015年 leilurong. All rights reserved.
//

/**
*  网络工具只负责获取数据后回调，不会处理数据
*/
import UIKit
//导入框架
import AFNetworking

// 网络请求的枚举
enum LRNetworkingMethod: String {
    case GET = "GET"
    case POST = "POST"
}
// 使用枚举来统一管理错误
enum LRNetworkToolError: Int {
    case emptyAccessToken = -1 // AccessToken没有值
    case emptyUid = -2   // Uid没有值
    
    // 枚举除了有成员之外,还可以有属性和方法
    // 将错误的code和错误的描述关联起来, 使用计算性属性,只有get(只读计算性属性)
    var errorDescription: String {
        get{
            // 判断不同的类型返回不同的错误信息
            switch self { //self是指 LRNetworkError
            case LRNetworkToolError.emptyAccessToken:
                return "accessToken没有值"
            case LRNetworkToolError.emptyUid:
                return "uid没有值"
            }
        }
    }
    //MARK - 定义一个方法,返回一个错误,根据枚举类型不一样返回不一样的错误
    func error() -> NSError {
        // domain: 域,自定义,表示错误的范围
        // code: 自定义,一般是负数开头,表示错误类型  self.rawValue是LRNetworkError枚举项的原型值-1，-2...
        // userInfo: 错误的附加信息,让别人明确错误的原因
        return NSError(domain: "com.huawei.network.error", code: self.rawValue, userInfo: ["errorDescription" : self.errorDescription])
    }
}
//MARK: - 回调闭包
typealias LRNetworkFinishedCallBack = (result: [String:AnyObject]?, error: NSError?) -> ()

class LRNetworkTool: AFHTTPSessionManager {

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    // MARK: - 单例方法 static静态方法即类方法
//    static let sharedNetworkTool: LRNetworkTool = {
//        // baseURL,api前面的内容是一样的
//        //https://api.weibo.com/oauth2/authorize?client_id=3428475514&redirect_uri=http://www.baidu.com/
//        let baseURL = NSURL(string: "https://api.weibo.com/")
//        let tool = LRNetworkTool(baseURL: baseURL)
//        return tool
//    }()
    
    
    ///MARK - 单例, 调用默认构造方法
    static let sharedNetworkTool: LRNetworkTool = LRNetworkTool()
    //private 不让别人访问构造方法
    private init () {
        // 没有初始化的属性
        let baseURL = NSURL(string: "https://api.weibo.com/")!
        // 在构造函数里面子类不能调用父类的便利构造函数,需要调用父类的指定构造函数
        //super.init(baseURL: baseURL)//点击init进去是一个convenience便利函数
        super.init(baseURL: baseURL, sessionConfiguration: nil)
        // 方法的调用必须在 super.init后，只有调用父类的super.init之后,对象才创建完毕,对象创建完毕才能调用对象的方法
        // 设置响应的序列化器,支持text/plain
        self.responseSerializer.acceptableContentTypes?.insert("text/plain")
        //self.responseSerializer.acceptableContentTypes = NSSet(objects: "application/json", "text/json", "text/javascript", "text/plain") as? Set<String>
    }
    
    // MARK: - 请求授权相关参数
    //App Key
    private let client_id = "4118539794"
    //授权回调地址
    let redirect_uri = "http://www.baidu.com/"
    // MARK: - 获取授权相关参数 上面的client_id也会用到
    //App Secret 秘钥
    let client_secret = "45155685b9d5bb2b8673170e80653b54"
    
    // MARK: - 拼接登陆界面的URL地址
    func oAuthURL()->NSURL{
    return NSURL(string: "https://api.weibo.com/oauth2/authorize?client_id=\(client_id)&redirect_uri=\(redirect_uri)")!
    }
    /// MARK: - 加载AccessToken
    func loadAccessToken(code: String, finished:LRNetworkFinishedCallBack) {
        //地址
        let URLString = "https://api.weibo.com/oauth2/access_token"
        //请求参数，字典
        let parameters = [
            "client_id": client_id,
            "client_secret": client_secret,
            "grant_type": "authorization_code",
            "code":	code, //授权获得的code值
            "redirect_uri": redirect_uri
        ]
        
        // 发送POST请求
        request(requestMethod: LRNetworkingMethod.POST, urlString: URLString, parameters: parameters, needAccessToken: false, finished: finished)
//        POST(URLString, parameters: parameters, success: { (_, result) -> Void in
//            //print("返回结果result: \(result)")
////            result: Optional({
////            "access_token" = "2.00JtaG1CM2yiUEcf66b60e01ETptTD";//访问令牌
////            "expires_in" = 157679999;//access_token的生命周期
////            "remind_in" = 157679999;//access_token的生命周期，即将废弃，建议使用上面那个
////            uid = 2129364155;// UID 用户身份证明(User Identification)
////            })
//            // 调用闭包, 需要将返回结果转成字典, 使用 as?,因为闭包的result参数是一个[String : AnyObject]?,说明可以传nil
//            let dict = result as? [String:AnyObject]
//            finished(result: dict, error: nil)
//            }) { (_, error) -> Void in
//                print("error: \(error)")
//                finished(result: nil, error: error)
//                
//        }
    }

    /// MAR: - 加载用户信息
    func loadUserInfo(finished:LRNetworkFinishedCallBack){
        // 1 获取AccessToken,判断AccessToken是否有值
//        if let access_Token = LRUserAccount.loadUserAccount()?.access_token {
//            //有值才进来
//            if let uid = LRUserAccount.loadUserAccount()?.uid {
//                // uid有值, 才能去发送请求,代码嵌套会比较多
//            }
//        }
//        // 1.获取AccessToken,判断AccessToken是否有值  guard守卫相反，没有值才进入大括号内
//        guard let access_token = LRUserAccount.loadUserAccount()?.access_token else {
//            // 能到这里面来uid没有值
//            // 最好是自定义错误返回给调用的人
//            // domain: 域,自定义,表示错误的范围
//            // code: 自定义,一般是负数开头,表示错误类型
//            // userInfo: 错误的附加信息,让别人明确错误的原因
//            //            let error = NSError(domain: "com.huawei.network", code: -1, userInfo: ["errorDescription" : "access_token没有值"])
//            //获取错误信息
//            let error = LRNetworkToolError.emptyAccessToken.error()
//            // 告诉调用者,网络请求出错
//            finished(result: nil, error: error)
//            return
//        }
        // 能到这里来说明 access_token 是有值的
        // 2.获取用户的uid guard守卫相反，没有值才进入大括号内
        guard let uid = LRUserAccount.loadUserAccount()?.uid else {
            //获取错误信息
            let error = LRNetworkToolError.emptyUid.error()
            // 告诉调用者,网络请求出错
            finished(result: nil, error: error)
            return
        }
        // 能到这里来说明uid是有值的.
        // 3.获取用户信息的url地址, 可以省略baseURL,AFN会自动帮我们加上 "https://api.weibo.com/"
        let urlString = "2/users/show.json"
        // 4.请求参数
        let parameters = [
            //"access_token": access_token, //访问令牌
            "uid": uid //用户身份证明
        ]
        // 5.发送请求获取用户数据
        request(requestMethod: LRNetworkingMethod.GET, urlString: urlString, parameters: parameters, needAccessToken: true, finished: finished)
//        GET(urlString, parameters: parameters, success: { (_, result) -> Void in
//            // 6.调用准备好的闭包
//            let dict = result as? [String: AnyObject]
//            finished(result: dict, error: nil)
//            }) { (_, error) -> Void in
//            // 6.调用准备好的闭包
//            finished(result: nil, error: error)
//        }
        
    }
    
    ///MARK - 从网络获取微博数据  since_id用于下拉刷新  max_id用于上拉刷新
    func loadStatusData(since_id: Int, max_id: Int, finished:LRNetworkFinishedCallBack) {
        //判断如果没有访问令牌的话
//        guard let access_token = LRUserAccount.loadUserAccount()?.access_token else {
//            //获取错误信息
//            let error = LRNetworkToolError.emptyAccessToken.error()
//            //将错误信息告诉调用者
//            finished(result: nil, error: error)
//            return
//        }
        //获取当前登录用户及其所关注（授权）用户的最新微博url
        let urlString = "2/statuses/home_timeline.json"
        //参数
//        var paramaters:[String: AnyObject] = ["access_token": access_token]
        var paramaters = [String: AnyObject]()//创建空字典
        
        if since_id > 0 {
            // 表示别人传了since_id, 下拉刷新微博数据
            paramaters["since_id"] = since_id
        }else if max_id > 0 {
            // 表示别人传了max_id, 上拉加载更多微博数据
            // 若指定此参数，则返回ID小于或等于max_id的微博,不需要等于的微博
            paramaters["max_id"] = max_id - 1//1减一防止重复加载max_id这条id的微博
        }
        //调试模式
        let debug = false
        if debug {
            //加载本地微博数据
            loadLocalStatusData(finished)
        }else{
            //发送请求 ，加载网络微博数据
            request(requestMethod: LRNetworkingMethod.GET, urlString: urlString, parameters: paramaters, needAccessToken: true, finished: finished)
//            GET(url, parameters: paramaters, success: { (_, result) -> Void in
//                //获取数据
//                let dict = result as? [String: AnyObject]
//                //结果回调
//                finished(result: dict, error: nil)
//                }) { (_, error) -> Void in
//                    //返回错误信息给调用者
//                    finished(result: nil, error: error)
//            }
        }
  
    }
    ///MARK - 加载本地微博数据
    func loadLocalStatusData(finished:LRNetworkFinishedCallBack) {
        //1 微博数据文件路径
        let filePath = NSBundle.mainBundle().pathForResource("statuses.json", ofType: nil)
        //2 加载到内存中，二进制
        let data = NSData(contentsOfFile: filePath!)
        //3 转成json,swift中的异常处理
        // throws表示方法会抛出异常
//        do {//解析json
//            let json = try? NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions(rawValue: 0))
//            //转成字典
//            let dict = json as? [String: AnyObject]
//            finished(result: dict, error: nil)
//        } catch { // 如果有异常,会到这里面来执行,程序不会崩溃,会一直往下走
//            print("json转换出现异常了")
//            let error = NSError(domain: "com.huawei.error.loadlocaleStatus", code: -3, userInfo: ["errorDescription" : "加载本地数据出错"])
//            finished(result: nil, error: error)
//        }
        
        // 强制try,和强制拆包一样,如果出现错误.程序立即停止运行
        let json = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions(rawValue: 0))
        let dict = json as? [String: AnyObject]
        finished(result: dict, error: nil)
    }
    
    ///MARK: - 加载评论
    func loadComments(id: Int,since_id: Int, max_id: Int, finished: LRNetworkFinishedCallBack) {
        //https://api.weibo.com/2/comments/show.json
        let urlString = "2/comments/show.json"
        var paramaters = ["id": id,
                          "count": 3]
        if since_id > 0 {
            paramaters["since_id"] = since_id//下拉刷新
        }else if max_id > 0 {
            paramaters["max_id"] = max_id - 1 //1减一防止上拉刷新重复加载max_id这条id的微博
        }
        request(requestMethod: LRNetworkingMethod.GET, urlString: urlString, parameters: paramaters, needAccessToken: true, finished: finished)
    }
    
    /// MARK: - 发布微博  status发布的微博内容
    func sendStatus(status: String, image: UIImage?, finished: LRNetworkFinishedCallBack) {
        //https://api.weibo.com/2/statuses/update.json
        let urlString = "2/statuses/update.json"
        // 判断是否有图片
        if let img = image {
            //发送带图片的微博
            sendImageStatus(status, image: img, finished: finished)
        }else{
            //设置参数
            let parameters = ["status": status]
            request(requestMethod: LRNetworkingMethod.POST, urlString: urlString, parameters: parameters, needAccessToken: true, finished: finished)
        }
    }
    /// MARK: - 发送带图片的微博
    func sendImageStatus(status: String, image: UIImage, finished: LRNetworkFinishedCallBack) {
        let URLString = "https://upload.api.weibo.com/2/statuses/upload.json"
    
        // 判断 access_token是否存在,存在就拼接,不存在就告诉调用者access_token 为空
        guard let access_token = LRUserAccount.loadUserAccount()?.access_token else {
            print("access_token 没有值")
            let error = LRNetworkToolError.emptyAccessToken.error()
            finished(result: nil, error: error)
            return
        }
        //access_token有值 添加参数
        let parameters = ["access_token": access_token,
                           "status": status]
        // appendPartWithFileData
        // 使用AFN上传图片,并发送微博
        // 3.请求参数
        POST(URLString, parameters: parameters, constructingBodyWithBlock: { (formData) -> Void in
            //解析图片成二进制数据
            let imageData = UIImagePNGRepresentation(image)!
            // 上传图片
            // data: 要上传的二进制
            // name: api里面指定的pic
            // fileName: 服务器保存的文件名,如果API有指定就按API指定的填,如果没有指定,可以随便填
            // mimeType: image/png, image/jpeg, image/gif
            formData.appendPartWithFileData(imageData, name: "pic", fileName: "", mimeType: "image/png")
            }, success: { (_, result) -> Void in
                let dict = result as? [String: AnyObject]
                finished(result: dict, error: nil)
            }) { (_, error: NSError) -> Void in
                finished(result: nil, error: error)
        }
    
    }
    /// MARK: - 评论微博
    func commentStatus(id: Int, comment: String, finished: LRNetworkFinishedCallBack) {
        //https://api.weibo.com/2/comments/create.json
        let urlString = "2/comments/create.json"
        //设置参数
        let parameters:[String: AnyObject] = [
                                              "id": id,
                                              "comment": comment]
        request(requestMethod: LRNetworkingMethod.POST, urlString: urlString, parameters: parameters, needAccessToken: true, finished: finished)
        
    }
    /// MARK: - 转发微博
    func repostStatus(id: Int, status: String, finished: LRNetworkFinishedCallBack) {
        //https://api.weibo.com/2/statuses/repost.json
        let urlString = "2/statuses/repost.json"
        //设置参数
        let parameters:[String: AnyObject] = ["status": status,
                                              "id": id]
        request(requestMethod: LRNetworkingMethod.POST, urlString: urlString, parameters: parameters, needAccessToken: true, finished: finished)
    }
    
    /**
    抽取AFN GET / POST 方法,网络请求的统一入口都是这个方法
    - parameter requestMethod:   请求方式
    - parameter urlString:       url地址
    - parameter needAccessToken: 是否需要访问令牌
    - parameter parameters:      参数
    - parameter finished:        回调的闭包
    */
    func request(requestMethod requestMethod: LRNetworkingMethod, urlString: String, var parameters: [String :AnyObject], needAccessToken:Bool, finished:LRNetworkFinishedCallBack) {
        // 需要accessToken,就拼接
        if needAccessToken {
            // 判断 access_token是否存在,存在就拼接,不存在就告诉调用者access_token 为空
            guard let access_token = LRUserAccount.loadUserAccount()?.access_token else {
                 print("access_token 没有值")
                let error = LRNetworkToolError.emptyAccessToken.error()
                finished(result: nil, error: error)
                return
            }
            //access_token有值 添加参数
            parameters["access_token"] = access_token
        }
        // 根据请求方式,发送对应的请求
        switch requestMethod {
        case .GET:
            GET(urlString, parameters: parameters, success: { (_, result) -> Void in
                    finished(result: result as? [String : AnyObject], error: nil)
                }, failure: { (_, error) -> Void in
                    finished(result: nil, error: error)
                    print("error = \(error)")
            })
        case .POST:
            POST(urlString, parameters: parameters, success: { (_, result) -> Void in
                    finished(result: result as? [String : AnyObject], error: nil)
                }, failure: { (_, error) -> Void in
                    finished(result: nil, error: error)
                    print("error = \(error)")
            })
        }
    }
  
}

























